package com.example.backend.repository.spec;

import com.example.backend.domain.entity.Ticket;
import com.example.backend.domain.entity.User;
import com.example.backend.domain.enums.Role;
import com.example.backend.domain.enums.TicketPriority;
import com.example.backend.domain.enums.TicketStatus;
import com.example.backend.domain.enums.TicketSource;
import com.example.backend.dto.TicketFilter;
import org.springframework.data.jpa.domain.Specification;

import java.time.Instant;

/**
 * 工单查询规格构建器
 * 支持复杂的多条件查询，优化数据库查询性能
 */
public class TicketSpecifications {

    /**
     * 根据筛选条件构建查询规格
     */
    public static Specification<Ticket> withFilter(TicketFilter filter) {
        if (filter == null) {
            return (root, query, cb) -> cb.conjunction();
        }
        
        Specification<Ticket> spec = (root, query, cb) -> cb.conjunction();
        
        // 基础条件
        spec = spec.and(hasStatus(filter.getStatus()));
        spec = spec.and(hasPriority(filter.getPriority()));
        spec = spec.and(hasSource(filter.getSource()));
        
        // 用户相关条件
        spec = spec.and(createdBy(filter.getCreatedById()));
        spec = spec.and(assignedTo(filter.getAssignedToId()));
        spec = spec.and(customer(filter.getCustomerId()));
        spec = spec.and(hasCategory(filter.getCategoryId()));
        
        // 时间范围条件
        spec = spec.and(createdFrom(filter.getCreatedFrom()));
        spec = spec.and(createdTo(filter.getCreatedTo()));
        spec = spec.and(updatedFrom(filter.getUpdatedFrom()));
        spec = spec.and(updatedTo(filter.getUpdatedTo()));
        spec = spec.and(dueFrom(filter.getDueFrom()));
        spec = spec.and(dueTo(filter.getDueTo()));
        
        // 文本搜索条件
        spec = spec.and(hasKeyword(filter.getKeyword()));
        spec = spec.and(hasTitleKeyword(filter.getTitleKeyword()));
        spec = spec.and(hasDescriptionKeyword(filter.getDescriptionKeyword()));
        
        // 布尔条件
        spec = spec.and(isPublic(filter.getIsPublic()));
        spec = spec.and(isEscalated(filter.getIsEscalated()));
        spec = spec.and(hasDueDate(filter.getHasDueDate()));
        
        // 数值范围条件
        spec = spec.and(minSatisfactionScore(filter.getMinSatisfactionScore()));
        spec = spec.and(maxSatisfactionScore(filter.getMaxSatisfactionScore()));
        
        return spec;
    }

    // 基础条件规格
    public static Specification<Ticket> hasStatus(TicketStatus status) {
        return (root, query, cb) -> status == null ? cb.conjunction() : cb.equal(root.get("status"), status);
    }

    public static Specification<Ticket> hasPriority(TicketPriority priority) {
        return (root, query, cb) -> priority == null ? cb.conjunction() : cb.equal(root.get("priority"), priority);
    }

    public static Specification<Ticket> hasSource(TicketSource source) {
        return (root, query, cb) -> source == null ? cb.conjunction() : cb.equal(root.get("source"), source);
    }

    // 用户相关条件规格
    public static Specification<Ticket> createdBy(Long userId) {
        return (root, query, cb) -> userId == null ? cb.conjunction() : cb.equal(root.get("createdBy").get("id"), userId);
    }

    public static Specification<Ticket> assignedTo(Long userId) {
        return (root, query, cb) -> userId == null ? cb.conjunction() : cb.equal(root.get("assignedTo").get("id"), userId);
    }

    public static Specification<Ticket> customer(Long customerId) {
        return (root, query, cb) -> customerId == null ? cb.conjunction() : cb.equal(root.get("customer").get("id"), customerId);
    }

    public static Specification<Ticket> hasCategory(Long categoryId) {
        return (root, query, cb) -> categoryId == null ? cb.conjunction() : cb.equal(root.get("category").get("id"), categoryId);
    }

    // 时间范围条件规格
    public static Specification<Ticket> createdFrom(Instant from) {
        return (root, query, cb) -> from == null ? cb.conjunction() : cb.greaterThanOrEqualTo(root.get("createdAt"), from);
    }

    public static Specification<Ticket> createdTo(Instant to) {
        return (root, query, cb) -> to == null ? cb.conjunction() : cb.lessThanOrEqualTo(root.get("createdAt"), to);
    }

    public static Specification<Ticket> updatedFrom(Instant from) {
        return (root, query, cb) -> from == null ? cb.conjunction() : cb.greaterThanOrEqualTo(root.get("updatedAt"), from);
    }

    public static Specification<Ticket> updatedTo(Instant to) {
        return (root, query, cb) -> to == null ? cb.conjunction() : cb.lessThanOrEqualTo(root.get("updatedAt"), to);
    }

    public static Specification<Ticket> dueFrom(Instant from) {
        return (root, query, cb) -> from == null ? cb.conjunction() : cb.greaterThanOrEqualTo(root.get("dueDate"), from);
    }

    public static Specification<Ticket> dueTo(Instant to) {
        return (root, query, cb) -> to == null ? cb.conjunction() : cb.lessThanOrEqualTo(root.get("dueDate"), to);
    }

    // 文本搜索条件规格
    public static Specification<Ticket> hasKeyword(String keyword) {
        return (root, query, cb) -> {
            if (keyword == null || keyword.trim().isEmpty()) {
                return cb.conjunction();
            }
            String pattern = "%" + keyword.trim() + "%";
            return cb.or(
                cb.like(cb.lower(root.get("title")), pattern.toLowerCase()),
                cb.like(cb.lower(root.get("description")), pattern.toLowerCase()),
                cb.like(cb.lower(root.get("ticketNumber")), pattern.toLowerCase())
            );
        };
    }

    public static Specification<Ticket> hasTitleKeyword(String keyword) {
        return (root, query, cb) -> {
            if (keyword == null || keyword.trim().isEmpty()) {
                return cb.conjunction();
            }
            String pattern = "%" + keyword.trim() + "%";
            return cb.like(cb.lower(root.get("title")), pattern.toLowerCase());
        };
    }

    public static Specification<Ticket> hasDescriptionKeyword(String keyword) {
        return (root, query, cb) -> {
            if (keyword == null || keyword.trim().isEmpty()) {
                return cb.conjunction();
            }
            String pattern = "%" + keyword.trim() + "%";
            return cb.like(cb.lower(root.get("description")), pattern.toLowerCase());
        };
    }

    // 布尔条件规格
    public static Specification<Ticket> isPublic(Boolean isPublic) {
        return (root, query, cb) -> isPublic == null ? cb.conjunction() : cb.equal(root.get("isPublic"), isPublic);
    }

    public static Specification<Ticket> isEscalated(Boolean isEscalated) {
        return (root, query, cb) -> isEscalated == null ? cb.conjunction() : cb.equal(root.get("isEscalated"), isEscalated);
    }

    public static Specification<Ticket> hasDueDate(Boolean hasDueDate) {
        return (root, query, cb) -> {
            if (hasDueDate == null) {
                return cb.conjunction();
            }
            return hasDueDate ? cb.isNotNull(root.get("dueDate")) : cb.isNull(root.get("dueDate"));
        };
    }

    // 数值范围条件规格
    public static Specification<Ticket> minSatisfactionScore(Integer minScore) {
        return (root, query, cb) -> minScore == null ? cb.conjunction() : cb.greaterThanOrEqualTo(root.get("satisfactionScore"), minScore);
    }

    public static Specification<Ticket> maxSatisfactionScore(Integer maxScore) {
        return (root, query, cb) -> maxScore == null ? cb.conjunction() : cb.lessThanOrEqualTo(root.get("satisfactionScore"), maxScore);
    }

    // 复合条件规格
    public static Specification<Ticket> hasStatusAndPriority(TicketStatus status, TicketPriority priority) {
        return hasStatus(status).and(hasPriority(priority));
    }

    public static Specification<Ticket> assignedToAndStatus(Long assignedToId, TicketStatus status) {
        return assignedTo(assignedToId).and(hasStatus(status));
    }

    public static Specification<Ticket> customerAndStatus(Long customerId, TicketStatus status) {
        return customer(customerId).and(hasStatus(status));
    }

    // 时间相关复合条件
    public static Specification<Ticket> createdInRange(Instant from, Instant to) {
        return createdFrom(from).and(createdTo(to));
    }

    public static Specification<Ticket> updatedInRange(Instant from, Instant to) {
        return updatedFrom(from).and(updatedTo(to));
    }

    public static Specification<Ticket> dueInRange(Instant from, Instant to) {
        return dueFrom(from).and(dueTo(to));
    }
    
    // ========== 数据权限过滤 ==========
    
    /**
     * 根据用户角色和ID创建数据权限过滤条件
     * @param currentUser 当前登录用户
     * @return 权限过滤规格
     */
    public static Specification<Ticket> withDataPermission(User currentUser) {
        if (currentUser == null) {
            // 如果没有当前用户，拒绝所有访问
            return (root, query, cb) -> cb.disjunction();
        }
        
        return (root, query, cb) -> {
            Role role = currentUser.getRole();
            Long userId = currentUser.getId();
            
            return switch (role) {
                case ADMIN -> 
                    // 管理员可以访问所有工单
                    cb.conjunction();
                
                case CUSTOMER -> 
                    // 客户只能访问自己创建的工单
                    cb.equal(root.get("customer").get("id"), userId);
                
                case AGENT -> {
                    // 客服只能访问分配给自己的工单
                    // 注意：这里需要处理assignedTo可能为null的情况
                    yield cb.and(
                        cb.isNotNull(root.get("assignedTo")),
                        cb.equal(root.get("assignedTo").get("id"), userId)
                    );
                }
                
                case SUPERVISOR -> {
                    // 主管可以访问分配给自己的工单
                    // 注意：当前不支持团队数据共享，因为User实体没有team字段
                    // 如果未来添加team字段，可以修改为：
                    // WHERE assigned_to_id IN (SELECT id FROM users WHERE team_id = currentUser.teamId)
                    //    OR assigned_to_id = currentUserId
                    yield cb.and(
                        cb.isNotNull(root.get("assignedTo")),
                        cb.equal(root.get("assignedTo").get("id"), userId)
                    );
                }
                
                case READONLY -> 
                    // 只读用户只能访问公开的工单
                    cb.equal(root.get("isPublic"), true);
                
                default -> 
                    // 未知角色，拒绝所有访问
                    cb.disjunction();
            };
        };
    }
    
    /**
     * 组合过滤条件和数据权限
     * @param filter 过滤条件
     * @param currentUser 当前用户
     * @return 组合后的规格
     */
    public static Specification<Ticket> withFilterAndPermission(TicketFilter filter, User currentUser) {
        return withFilter(filter)
                .and(withDataPermission(currentUser));
    }
    
    /**
     * 创建只包含数据权限的查询（不包含其他过滤条件）
     * @param currentUser 当前用户
     * @return 权限规格
     */
    public static Specification<Ticket> permissionOnly(User currentUser) {
        return withDataPermission(currentUser);
    }
}


